/*
 * 作者		www.TheWk.cn.vc
 * 开发环境	Windows7 64位 MyEclipse8.6 JDK1.6.0_45
 * 开发日期	2014年6月10日
 */
package common.log;

import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import common.vo.SessionAdminVo;

/**
 * <hr/>
 * 
 * @author www.TheWk.cn.vc
 * @version 1.0 2014年6月10日
 * @class common.crudlog.CRUDLogger
 */
//@Aspect
public class MgrCRUDLogger {

	private Logger                  logger          = LoggerFactory.getLogger(this.getClass());

	private static final String     Method_GetVo    = "getVo_Auto";
	private static final String     Method_QueryVos = "queryVos_Auto";
	private static final DateFormat Date_Formatter  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	/**
	 * 记录新增的日志
	 */
	@Around(value = "execution(public long com.dicunicom.upl.mgr.*Mgr*.save(..))")
	public Object doRecordSaveLog(ProceedingJoinPoint jp) throws Throwable {
		if (jp.getArgs() == null || jp.getArgs().length != 1) {// 入参不对,则不记录
			return jp.proceed();
		}
		long result = (Long) jp.proceed();
		if (result <= 0) {
			return result;
		}
		Object target = jp.getTarget(); // 取得代理对象
		Object addVo = jp.getArgs()[0]; // 取得新增的值对象
		String tableName = getTableName(addVo);
		if (StringUtils.isBlank(tableName)) {
			return result;
		}
		Object pkValue = getPkFieldValue(addVo);
		if (pkValue == null) {
			return result;
		}
		Object dbVo = target.getClass().getMethod(Method_GetVo, pkValue.getClass(), int.class).invoke(target, pkValue, 0);

		if (logger.isInfoEnabled()) {
			logger.info("新增:[" + tableName + "]开始");
			logger.info("IP地址:[" + getClientIpAddr() + "],用户:[" + getClientUserLoginName() + "]");
			logger.info("入参:[" + addVo + "]");
		}
		Field[] voFields = dbVo.getClass().getDeclaredFields();
		for (Field voField : voFields) {
			if (logger.isInfoEnabled()) {
				logger.info("列名:[" + getColumnName(voField) + "],新值:[" + getFieldValue(voField, dbVo) + "]");
			}
		}
		if (logger.isInfoEnabled()) {
			logger.info("=================================================");
		}
		return result;
	}

	/**
	 * 记录删除日志
	 */
	@Around(value = "execution(public long com.dicunicom.upl.mgr.*Mgr*.delete(..))")
	public Object doRecordDeleteLog(ProceedingJoinPoint jp) throws Throwable {
		if (jp.getArgs() == null || jp.getArgs().length != 1) {
			return jp.proceed();
		}
		Object target = jp.getTarget(); // 取得代理对象
		Object deleteId = jp.getArgs()[0]; // 取得删除的Id
		if (deleteId == null) {
			return jp.proceed();
		}
		Object dbVo = target.getClass().getMethod(Method_GetVo, deleteId.getClass(), int.class).invoke(target, deleteId, 0);
		long result = (Long) jp.proceed();
		if (result > 0) {
			String tableName = getTableName(dbVo);
			if (StringUtils.isBlank(tableName)) {
				return result;
			}
			if (logger.isInfoEnabled()) {
				logger.info("删除:[" + tableName + "]");
				logger.info("IP地址:[" + getClientIpAddr() + "],用户:[" + getClientUserLoginName() + "]");
				logger.info("入参:[" + deleteId + "]");
			}
			Field[] voFields = dbVo.getClass().getDeclaredFields();
			for (Field voField : voFields) {
				if (logger.isInfoEnabled()) {
					logger.info("列名:[" + getColumnName(voField) + "],旧值:[" + getFieldValue(voField, dbVo) + "]");
				}
			}
			if (logger.isInfoEnabled()) {
				logger.info("=================================================");
			}
		}
		return result;
	}

	/**
	 * 记录批量删除日志
	 */
	@SuppressWarnings("rawtypes")
	@Around(value = "execution(public long com.dicunicom.upl.mgr.*Mgr*.deleteBatch(..))")
	public Object doRecordDeleteBatchLog(ProceedingJoinPoint jp) throws Throwable {
		if (jp.getArgs() == null || jp.getArgs().length != 1) {
			return jp.proceed();
		}
		Object target = jp.getTarget(); // 取得代理对象
		Object deleteSearch = jp.getArgs()[0]; // 取得删除的条件
		if (deleteSearch == null) {
			return jp.proceed();
		}
		List dbVos = (List) target.getClass().getMethod(Method_QueryVos, deleteSearch.getClass(), int.class).invoke(target, deleteSearch, 0);
		long result = (Long) jp.proceed();
		if (result > 0) {
			if (logger.isInfoEnabled()) {
				String clientIpAddr = getClientIpAddr();
				logger.info("批量删除:[" + getTableName(dbVos.get(0)) + "]开始");
				logger.info("IP地址:[" + clientIpAddr + "]");
				logger.info("入参:[" + deleteSearch + "]");
			}
			for (Object dbVo : dbVos) {
				Field[] voFields = dbVo.getClass().getDeclaredFields();
				for (Field voField : voFields) {
					if (logger.isInfoEnabled()) {
						logger.info("字段名称:[" + getColumnName(voField) + "],旧字段值:[" + getFieldValue(voField, dbVo) + "]...");
					}
				}
			}
			if (logger.isInfoEnabled()) {
				logger.info("=================================================");
			}
		}
		return result;
	}

	/**
	 * 记录更新日志
	 */
	@Around(value = "execution(public long com.dicunicom.upl.mgr.*Mgr*.update(..))")
	public Object doRecordUpdateLog(ProceedingJoinPoint jp) throws Throwable {
		if (jp.getArgs() == null || jp.getArgs().length != 1) {
			return jp.proceed();
		}
		Object target = jp.getTarget(); // 取得代理对象
		Object updateVo = jp.getArgs()[0]; // 取得更新的值对象
		String tableName = getTableName(updateVo);
		if (StringUtils.isBlank(tableName)) {
			return jp.proceed();
		}
		Object pkValue = getPkFieldValue(updateVo);
		if (pkValue == null) {
			return jp.proceed();
		}
		Object dbOldVo = target.getClass().getMethod(Method_GetVo, pkValue.getClass(), int.class).invoke(target, pkValue, 0);
		long result = (Long) jp.proceed();
		if (result > 0) {
			if (logger.isInfoEnabled()) {
				logger.info("更新:[" + tableName + "]开始...");
				logger.info("IP地址:[" + getClientIpAddr() + "],用户:[" + getClientUserLoginName() + "]");
				logger.info("入参:[" + updateVo + "]");
			}
			Object dbNewVo = target.getClass().getMethod(Method_GetVo, pkValue.getClass(), int.class).invoke(target, pkValue, 0);
			Field[] voFields = dbOldVo.getClass().getDeclaredFields();
			for (Field voField : voFields) {
				if (logger.isInfoEnabled()) {
					logger.info("字段名称:[" + getColumnName(voField) + "],旧字段值:[" + getFieldValue(voField, dbOldVo) + "],新字段值[" + getFieldValue(voField, dbNewVo) + "]...");
				}
			}
			if (logger.isInfoEnabled()) {
				logger.info("=================================================");
			}
		}
		return result;
	}

	/**
	 * 记录批量更新日志
	 */
	@SuppressWarnings("rawtypes")
	@Around(value = "execution(public long com.dicunicom.upl.mgr.*Mgr*.updateBatch(..))")
	public Object doRecordUpdateBatchLog(ProceedingJoinPoint jp) throws Throwable {
		if (jp.getArgs() == null || jp.getArgs().length != 2) {
			return jp.proceed();
		}
		Object target = jp.getTarget(); // 取得代理对象
		Object updateVo = jp.getArgs()[0]; // 取得更新的值对象
		Object updateSearch = jp.getArgs()[1]; // 取得更新的条件
		if (updateVo == null) {
			return jp.proceed();
		}
		List dbOldVos = (List) target.getClass().getMethod(Method_QueryVos, updateSearch.getClass(), int.class).invoke(target, updateSearch, 0);
		long result = (Long) jp.proceed();
		if (result > 0) {
			if (logger.isInfoEnabled()) {
				logger.info("批量更新:[" + getTableName(dbOldVos.get(0)) + "]开始...");
				logger.info("IP地址:[" + getClientIpAddr() + "],用户:[" + getClientUserLoginName() + "]");
				logger.info("入参:[" + updateSearch + "]");
			}

			for (Object dbOldVo : dbOldVos) {
				Object pkValue = getPkFieldValue(dbOldVo);
				Object dbNewVo = target.getClass().getMethod(Method_GetVo, pkValue.getClass(), int.class).invoke(target, pkValue, 0);
				Field[] voFields = dbOldVo.getClass().getDeclaredFields();
				for (Field voField : voFields) {
					if (logger.isInfoEnabled()) {
						logger.info("字段名称:[" + getColumnName(voField) + "],旧字段值:[" + getFieldValue(voField, dbOldVo) + "],新字段值[" + getFieldValue(voField, dbNewVo) + "]...");
					}
				}
			}
			if (logger.isInfoEnabled()) {
				logger.info("=================================================");
			}
		}
		return result;
	}

	/**
	 * 获取连接的IP地址
	 */
	private String getClientIpAddr() {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		final String UNKNOWN = "unknown";
		String ip = request.getHeader("x-forwarded-for");
		if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip))
			ip = request.getHeader("Proxy-Client-IP");
		if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip))
			ip = request.getHeader("WL-Proxy-Client-IP");
		if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip))
			ip = request.getRemoteAddr();
		return ip;
	}

	/**
	 * 获取当前操作人员的登录名称
	 */
	private String getClientUserLoginName() {
		final String empty = "";
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		
		SessionAdminVo sessionAdmin = (SessionAdminVo) request.getSession().getAttribute("USERSESSION");
		if (sessionAdmin == null) {
			return empty;
		}
		return sessionAdmin.getLoginName();
	}

	/**
	 * 获取表名,(如果没有表名,则输出类名的简写)
	 */
	private String getTableName(Object obj) {
		if (obj == null) {
			return null;
		}
		Table tableAnnotation = obj.getClass().getAnnotation(Table.class);
		return tableAnnotation == null ? obj.getClass().getSimpleName() : tableAnnotation.name();
	}

	/**
	 * 获取主键的值
	 */
	private Object getPkFieldValue(Object obj) throws Throwable {
		if (obj == null) {
			return null;
		}
		for (Field field : obj.getClass().getDeclaredFields()) {
			Id idAnnotation = field.getAnnotation(Id.class);
			if (idAnnotation != null) {
				field.setAccessible(true);
				return field.get(obj);
			}
		}
		return null;
	}

	/**
	 * 获取字段对应的列名,如果对应的列名为空,则返回字段的名称
	 */
	private String getColumnName(Field field) {
		if (field == null) {
			return null;
		}
		Column columnAnnotation = field.getAnnotation(Column.class);
		return columnAnnotation == null ? field.getName() : columnAnnotation.name();
	}

	/**
	 * 根据字段的类型,获取字段的值
	 */
	private Object getFieldValue(Field field, Object target) throws Throwable {
		field.setAccessible(true);
		Object fieldValue = field.get(target);
		if (fieldValue == null) {
			return null;
		}
		if (field.getType() == java.util.Date.class) {
			return Date_Formatter.format((Date) fieldValue);
		}
		return fieldValue;
	}
}
